package com.lujianfei.mqtt

import android.Manifest
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.content.res.Resources
import android.location.Location
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.os.Looper
import android.provider.Settings
import android.util.Log
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.ToastUtils
import com.lujianfei.mqtt.callback.MqttServiceCallBack
import com.lujianfei.mqtt.chat.*
import com.lujianfei.mqtt.common.KVSpUtils
import com.lujianfei.mqtt.databinding.ActivityMainBinding
import com.lujianfei.mqtt.ktx.toDataClass
import com.lujianfei.mqtt.ktx.toJsonString
import com.lujianfei.mqtt.login.mvvm.UserInfo
import com.lujianfei.mqtt.net.config.USER_ACCOUNT
import com.lujianfei.mqtt.service.MQTTService
import com.tencent.map.geolocation.TencentLocation
import com.tencent.map.geolocation.TencentLocationListener
import com.tencent.map.geolocation.TencentLocationManager
import com.tencent.map.geolocation.TencentLocationRequest
import com.tencent.tencentmap.mapsdk.maps.CameraUpdateFactory
import com.tencent.tencentmap.mapsdk.maps.LocationSource
import com.tencent.tencentmap.mapsdk.maps.MapView
import com.tencent.tencentmap.mapsdk.maps.TencentMap
import com.tencent.tencentmap.mapsdk.maps.model.*
import dagger.hilt.android.AndroidEntryPoint
import me.jessyan.autosize.AutoSizeCompat
import me.jessyan.autosize.AutoSizeConfig


/**
 * @Author: wn
 * @Date: 2024/4/17 15:44
 * @Description: 主界面  地图 + MQTT
 * 定位 TencentLocationListener
 * 展示定位点  实现 LocationSource 接口
 */
@Suppress("DEPRECATED_IDENTITY_EQUALS")
@AndroidEntryPoint
class MainActivity : BaseActivity<ActivityMainBinding>(), TencentLocationListener, LocationSource {

  override fun getLayoutRes() = R.layout.activity_main

  private val mainViewModel by viewModels<MainViewModel>()

  /**
   * 腾讯地图
   */
  // mapView 与其生命周期 负责 地图的显示
  private val mapView: MapView by lazy {
    mBinding.mapView
  }
  private val mMap: TencentMap by lazy {
    mapView.map
  }

  // 定位相关
  private var mLocationManager: TencentLocationManager? = null
  private var mLocationRequest: TencentLocationRequest? = null

  private lateinit var mActivityResult: ActivityResultLauncher<Intent>

  /**
   * 开始定位
   */
  private fun startLocation() {
    mLocationManager?.requestLocationUpdates(mLocationRequest, this)
  }

  /**
   * 停止定位
   */
  private fun stopLocation() {
    mLocationManager?.removeUpdates(this)
  }

  override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray,
  ) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == RC_PERMISSION_LOCATION) {
      if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        startLocation()
      } else {
        if (shouldShowRequestPermissionRationale(PERMISSION_LOCATION)) {
          showPermissionRationale()
        } else {
          showSettingDialog()
        }
      }
    }
  }

  private fun checkAndRequestLocationPermission(): Boolean {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
      return true
    }
    if (PackageManager.PERMISSION_GRANTED ==
      ContextCompat.checkSelfPermission(this, PERMISSION_LOCATION)
    ) {
      return true
    }
    if (shouldShowRequestPermissionRationale(PERMISSION_LOCATION)) {
      showPermissionRationale()
    } else {
      requestPermissions(arrayOf(PERMISSION_LOCATION), RC_PERMISSION_LOCATION)
    }
    return false
  }

  private fun showPermissionRationale() {
    AlertDialog.Builder(this)
      .setMessage("请打开定位权限")
      .setNegativeButton("取消", null)
      .setPositiveButton("确定") { _, _ ->
        requestPermissions(arrayOf(PERMISSION_LOCATION), RC_PERMISSION_LOCATION)
      }
      .show()
  }

  private fun showSettingDialog() {
    AlertDialog.Builder(this)
      .setMessage("没有定位权限，请在设置中打开。")
      .setPositiveButton("设置") { _, _ -> openSetting() }
      .show()
  }

  private fun openSetting() {
    mActivityResult.launch(
      Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
        data = Uri.fromParts("package", packageName, null)
      })
  }

  private fun initTencentMap() {
    mMap.apply {
      // 开启多窗口模式 即同时显示多个标题
      enableMultipleInfowindow(true)
      // 地图上设置定位数据源
      setLocationSource(this@MainActivity)
      //设置当前位置可见
      isMyLocationEnabled = true
      // 点击定位点
      setMyLocationClickListener {
        ToastUtils.showShort("当前用户是:${userInfo?.account}")
        true
      }
    }
    mLocationManager = TencentLocationManager.getInstance(this)
    mLocationRequest = TencentLocationRequest.create().apply {
      interval = 1 * 1000
      isAllowGPS = true
      requestLevel = TencentLocationRequest.REQUEST_LEVEL_ADMIN_AREA
      isAllowDirection = true
      isIndoorLocationMode = true
    }

    mActivityResult =
      registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        // 在设置中不管是否打开权限，返回后 resultCode 始终是 RESULT_CANCELED
        if (PackageManager.PERMISSION_GRANTED ==
          ContextCompat.checkSelfPermission(this, PERMISSION_LOCATION)
        ) {
          startLocation()
        }
      }
  }

  /**
   * chat 界面
   */
  private val msgList = ArrayList<Msg>()
  private lateinit var adapter: MsgAdapter

  override fun initView() {
    super.initView()
    mBinding.apply {
      vm = mainViewModel
      send.setOnClickListener {
        publish()
      }
      // 实例化 adapter
      adapter = MsgAdapter(msgList)
      recyclerView.layoutManager = LinearLayoutManager(this@MainActivity)
      recyclerView.adapter = adapter
    }
//        initMap()
    initTencentMap()
  }

  override fun onLocationChanged(t_location: TencentLocation?, error: Int, reason: String?) {
    // 地图移动
    t_location?.apply {

      moveTencentMap(latitude, longitude)

      // 其中 locationChangeListener 为 LocationSource.active 返回给用户的位置监听器
      // 用户通过这个监听器就可以设置地图的定位点位置
      // 其中 locationChangeListener 为 LocationSource.active 返回给用户的位置监听器
      // 用户通过这个监听器就可以设置地图的定位点位置
      if (error === TencentLocation.ERROR_OK && locationChangedListener != null) {
        //设置经纬度
        location.latitude = t_location.latitude
        location.longitude = t_location.longitude
        //设置精度，这个值会被设置为定位点上表示精度的圆形半径
        location.accuracy = t_location.accuracy
        //设置定位标的旋转角度，注意 tencentLocation.getBearing() 只有在 gps 时才有可能获取
        //location.setBearing((float) tencentLocation.getBearing());
        //设置定位标的旋转角度，注意 tencentLocation.getDirection() 返回的方向，仅来自传感器方向，如果是gps，则直接获取gps方向
        location.bearing = t_location.direction.toFloat()

        //将位置信息返回给地图
        locationChangedListener?.onLocationChanged(location)
      }

      // MQTT  发送定位信息  Json
      userInfo?.apply {
        val gpsPayLoad = GpsPayLoad(
          id,
          account,
          color,
          longitude,
          latitude,
//          teamName
        )
        val jsonStr = gpsPayLoad.toJsonString() ?: "null"
        mMQTTService?.publish(jsonStr, Constant.MQ.publish_pos_Topic)
      }
    }
  }

  override fun onStatusUpdate(name: String?, status: Int, desc: String?) {
//    LogUtils.i(TAG, "onStatusUpdate。name: $name status: $status desc: $desc")
  }

  /**
   * 展示定位点
   */
  private val location: Location by lazy {
    Location("LongPressLocationProvider")
  }
  private var locationChangedListener: LocationSource.OnLocationChangedListener? = null
  override fun activate(onLocationChangedListener: LocationSource.OnLocationChangedListener?) {
    //这里我们将地图返回的位置监听保存为当前 Activity 的成员变量
    locationChangedListener = onLocationChangedListener
    //开启定位
    val err: Int? = mLocationManager?.requestLocationUpdates(
      mLocationRequest, this, Looper.myLooper()
    )
    when (err) {
      1 -> Toast.makeText(
        this,
        "设备缺少使用腾讯定位服务需要的基本条件",
        Toast.LENGTH_SHORT
      ).show()
      2 -> Toast.makeText(
        this,
        "manifest 中配置的 key 不正确", Toast.LENGTH_SHORT
      ).show()
      3 -> Toast.makeText(
        this,
        "自动加载libtencentloc.so失败", Toast.LENGTH_SHORT
      ).show()
      else -> {}
    }
  }

  override fun deactivate() {
    //当不需要展示定位点时，需要停止定位并释放相关资源
    mLocationManager?.removeUpdates(this)
    mLocationManager = null
    mLocationRequest = null
    locationChangedListener = null
  }

  /**
   * 添加 marker
   * 目前只添加一次
   */
  private val markers = mutableMapOf<String, Marker>()
  private fun setMarker(latitude: Double, longitude: Double, color: String, title: String) {
    val lat = LatLng(latitude, longitude)
    val marker = markers[title]
    // map 中 不存在  添加 maker
    if (marker == null) {
      // 给Marker添加上浮动画
      val animation: Animation = ScaleAnimation(0f, 1f, 0f, 1f)
      animation.duration = 600

      mMap.addMarker(
        MarkerOptions(lat)
          .title(title)
          .icon(
            BitmapDescriptorFactory.defaultMarker(
              colorFilter[color] ?: BitmapDescriptorFactory.HUE_RED
            )
          )
      ).apply {
        showInfoWindow() // 显示信息窗口 即标题
        setAnimation(animation)
        startAnimation()
        // 添加到 map 中
        markers[title] = this
      }
    } else {  // map 中 存在  移动位置
      marker.position = lat
    }
  }

  private fun moveTencentMap(latitude: Double, longitude: Double) {
    val cameraSigma = CameraUpdateFactory.newCameraPosition(
      CameraPosition(
        LatLng(latitude, longitude),  // 中心点坐标，地图目标经纬度
        12f,  // 目标缩放级别
        0f,  // 目标倾斜角[0.0 ~ 45.0] (垂直地图时为0)
        0f
      )
    ) // 目标旋转角 0~360° (正北方为0)
    mMap.moveCamera(cameraSigma) // 移动地图
  }

  override fun onResume() {
    super.onResume()
    Log.i(TAG, "onStart")
    // 开启 MQ service
    bindService(
      Intent(this, MQTTService::class.java),
      mConnection,
      Context.BIND_AUTO_CREATE
    )
    // 在activity执行onResume时执行mMapView. onResume ()，实现地图生命周期管理
//        mMapView?.onResume()
    // 开启定位
    if (checkAndRequestLocationPermission()) {
      startLocation()
    }
    // 显示地图
    mapView.onResume()
  }

  override fun onPause() {
    super.onPause()
    // 在activity执行onPause时执行mMapView. onPause ()，实现地图生命周期管理
//        mMapView?.onPause()
    mapView.onPause()
  }

  override fun onDestroy() {
    super.onDestroy()
    Log.i(TAG, "onStop")
    // 断开 MQ service
    if (mBound) {
      unbindService(mConnection)
      mBound = false
    }
    // 在activity执行onDestroy时执行mMapView.onDestroy()，实现地图生命周期管理
//        mLocationClient.stop()
//        mMap?.isMyLocationEnabled = false
//        mMapView?.onDestroy()
//        mMapView = null
    // 停止定位
    stopLocation()
    mapView.onDestroy()
  }

  // MQTT
  private var mMQTTService: MQTTService? = null
  private var mBound = false

  private val userInfo by lazy {
    KVSpUtils.getString(USER_ACCOUNT)?.toDataClass<UserInfo>()
  }

  /**
   * 发送 输入的文字
   */
  private fun publish() {
    mBinding.apply {
      if (userInfo == null) return@apply ToastUtils.showShort("用户异常 无法输入")
      userInfo?.apply {
        if (inputText.text.isNullOrEmpty()) {
          ToastUtils.showShort("请输入内容")
          return
        }
        val content = inputText.text.toString()
        // 自己
        notifyAdapter(content, account, Msg.TYPE_SET)
        //清空输入框中的内容
        inputText.setText("")
        // MQTT  传递 Json
        val messagePayLoad = MessagePayLoad(account, content, id, teamId, teamName, color)
        val jsonStr = messagePayLoad.toJsonString() ?: "null"
        mMQTTService?.publish(jsonStr, Constant.MQ.publish_msg_Topic)
      }
    }
  }

  private val mConnection = object : ServiceConnection {
    override fun onServiceDisconnected(name: ComponentName?) {
      mBound = false
      Log.i(TAG, "onServiceDisconnected $name")
    }

    override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
      Log.i(TAG, "onServiceConnected $name $service")
      if (service is MQTTService.CustomBinder) {
        mMQTTService = service.service
        // service 向 activity 通信
        mMQTTService?.setOnCallback(mMqttServiceCallBack)
        mBound = true
      }
    }
  }

  // MQTT  接收消息
  private val mMqttServiceCallBack = object : MqttServiceCallBack {
    override fun onMessageReceive(message: String?, type: String) {
      LogUtils.i(TAG, "onMessageReceive $message--$type")
      when (type) {
        "msg" -> { // 聊天消息
          message?.also {
            it.toDataClass<MessagePayLoad>()?.apply {
              // 自己发送的消息
              if (this@MainActivity.userInfo?.account == sendName) return
              // 是否所有人 都接收  isAll == 1
              if (isAll == 1) return notifyAdapter(content, sendName, Msg.TYPE_RECEIVED)
              // 不是同一组的不显示
              if (this@MainActivity.userInfo?.teamName != teamName) return
              // 接收的消息 更新列表
              notifyAdapter(content, sendName, Msg.TYPE_RECEIVED)

            }
          }
        }
        "gps" -> { // 是定位消息
          message?.also {
            it.toDataClass<GpsPayLoad>()?.apply {
              // 自己发送的消息
              if (this@MainActivity.userInfo?.account == userName) return
              // 不是同一组的不显示
              //            if (this@MainActivity.userInfo?.teamName != teamName) return
              // 添加 Marker 携带颜色
              setMarker(latitude, longitude, color, userName)
            }
          }
        }
        else -> { // 置顶消息
          message?.also {
            it.toDataClass<TopMsgPayLoad>()?.apply {
              mainViewModel.topMessage.set(missionRecord)
            }
          }
        }
      }
    }
  }

  /**
   * 更新 聊天列表
   */
  private fun notifyAdapter(content: String, name: String, type: Int) {
    val msg = Msg(content, name, type)
    msgList.add(msg)
    // 当有新消息时，就刷新 RecyclerView 中的显示
    adapter.notifyItemInserted(msgList.size - 1)
    // 将显示定位到最后一行
    mBinding.recyclerView.scrollToPosition(msgList.size - 1)
  }

  /**
   * 解决屏幕适配方案 时  横屏时 字体 图标放大的问题
   */
  override fun getResources(): Resources {
    val designWidth = AutoSizeConfig.getInstance().screenWidth
    val designHeight = AutoSizeConfig.getInstance().screenHeight
    val isBaseOnWidth = designWidth <= designHeight
    if (Looper.myLooper() == Looper.getMainLooper()) {
      AutoSizeCompat.autoConvertDensity(super.getResources(), 360.0F, isBaseOnWidth)
    }
    return super.getResources()
  }

  companion object {
    const val TAG = "MainActivity_MQ"
    private const val PERMISSION_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION
    private const val RC_PERMISSION_LOCATION = 10
  }
  // region 百度地图
  /*  // 地图
    private val mMapView: MapView? by lazy {
        mBinding.bmapView
    }

    private val mMap: BaiduMap? by lazy {
        mMapView?.map
    }
    // 定位
    private val mLocationClient : LocationClient by lazy {
        // client 实例化之前
        LocationClient.setAgreePrivacy(true)
        LocationClient(context)
    }
    // 第一次定位
   private var isFirstLocate = true*/
  /**
   * 地图初始化
   */
  /*   private fun initMap(){
         // 设置地图的缩放级别
         val builder =  MapStatus.Builder().apply {
             zoom(16.0f)
         }
         mMap?.setMapStatus(MapStatusUpdateFactory.newMapStatus(builder.build()))
         // 卫星地图
         mMap?.mapType = BaiduMap.MAP_TYPE_NORMAL
         // 开启地图定位图层
         mMap?.isMyLocationEnabled = true
         mMap?.uiSettings?.apply {
             isZoomGesturesEnabled = true // 开启地图缩放
             isRotateGesturesEnabled = true // 允许地图旋转手势
             isCompassEnabled = true // 开启指南针
         }
         // 定位初始化
         // 通过LocationClientOption设置LocationClient相关参数
         val option = LocationClientOption().apply {


             // 打开gps
             openGps = true
             // 当GPS 有效时 按照 151次频率输出gps结果
             isLocationNotify = true
             // 设置 在 stop时 杀死这个进程
             isIgnoreKillProcess = false
             // 设置是否需要 POI  结果
             setIsNeedLocationPoiList(false)
             // 设置坐标类型
             setCoorType("bd09ll")
             // 连续定位请求的间隔 大于 1000ms 默认0 定位一次
             setScanSpan(1000)
             // 是否需要地址信息 默认不需要
             setIsNeedAddress(true)
             // 获取位置描述信息
             setIsNeedLocationDescribe(true)
             // 是否需要 海拔信息
             setIsNeedAltitude(true)
             wifiCacheTimeOut = 5 * 60 * 1000
             // 设置定位模式 高精度 低功耗 仅设备  默认高精度
             locationMode = LocationClientOption.LocationMode.Hight_Accuracy;
             // option.setLocationMode(LocationClientOption.LocationMode.Battery_Saving);
             // option.setLocationMode(LocationClientOption.LocationMode.Device_Sensors);
         }
         // 设置locationClientOption
         mLocationClient.locOption = option

         // 注册LocationListener监听器
 //        MyLocationListeners myLocationListener = new MyLocationListeners()
         mLocationClient.registerLocationListener{
             // mapView 销毁后不在处理新接收的位置
             if (it == null) {
                 return@registerLocationListener
             }
             // 无法获取有效定位
             val errorCode = it.locType
             if(errorCode == 62) return@registerLocationListener ToastUtils.showShort("无法获取有效定位")
             // 如果是第一次定位
             if (isFirstLocate) {
                 isFirstLocate = false
                 val ll = LatLng(it.latitude,it.longitude )
                 // 给地图设置状态
                 mMap?.animateMapStatus(MapStatusUpdateFactory.newLatLng(ll))
             }

             val locData = MyLocationData.Builder()
                 .accuracy(it.radius)
                 // 此处设置开发者获取到的方向信息，顺时针0-360
                 .direction(it.direction)
                 .latitude(it.latitude)
                 .longitude(it.longitude)
                 .build()
             mMap?.setMyLocationData(locData);
 //            it.city
             LogUtils.e(it.latitude,it.longitude)
         }
         //开启地图定位图层
         mLocationClient.start()
     }*/
  // endregion
}
